﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
using FrontDisplay.NativeMethods;
using Microsoft.Win32;
using Def.Log;

namespace FrontDisplay
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private System.Windows.Forms.NotifyIcon _notifyIcon;
        private ParametersWindow _parametersWindow;
        private static List<IPlugin> _plugins;
        private DispatcherTimer _changeThemeTimer;
        private readonly HotkeyCollection _hotkeys = new HotkeyCollection();
        private Hotkey _changeThemeHotkey;
        
        public DispatcherTimer ChangeThemeTimer
        {
            get { return _changeThemeTimer; }
        }

        public static IEnumerable<IPlugin> Plugins
        {
            get { return _plugins.AsReadOnly(); }
        }

        public static T GetPlugin<T>() where T : class, IPlugin
        {
            foreach (IPlugin plugin in Plugins)
            {
                if (plugin.GetType() == typeof(T))
                {
                    return (T)plugin;
                }
            }
            return null;
        }

        public MainWindow()
        {
            Logger.Debug("MainWindow constructor begin");
            InitializeComponent();

            Loaded += MainWindowLoaded;
            Closed += MainWindowClosed;
            Deactivated += MainWindowDeactivated;

            WindowStartupLocation = WindowStartupLocation.Manual;

            //NOTE: Affects performance, should be false.
            AllowsTransparency = false;

            Topmost = Global.Config.IsTopmost;

            if (Global.Config.IsFullScreen)
            {
                WindowStyle = WindowStyle.None;
                ResizeMode = ResizeMode.NoResize;
            }
            else
            {
                WindowStyle = WindowStyle.ToolWindow;
                Width = 400;
                Height = 250;
                WindowStartupLocation = WindowStartupLocation.CenterScreen;
            }

            Cursor = Global.Config.IsShowMouseCursor ? System.Windows.Input.Cursors.None : System.Windows.Input.Cursors.Arrow;

#if !DEBUG
            ShowInTaskbar = false;
#else
            ShowInTaskbar = true;
#endif
            SizeChanged += delegate { UpdateWindowPosition(); };

            Logger.Debug("MainWindow constructor end");
        }

        private void MainWindowLoaded(object sender, RoutedEventArgs e)
        {
            Logger.Debug("MainWindow loaded");

            this.AddExWindowStyle(WinApi.WS_EX_TOOLWINDOW);

            SystemEvents.DisplaySettingsChanged += SystemEventsDisplaySettingsChanged;

            InitializePlugins();

            UpgradeConfig();

            UpdateWindowPosition();

            StartPlugins();

            ContextMenu.Items.Insert(0, new Separator());

            MenuPage.Instance.Initialize(_plugins, ContextMenu);

            _notifyIcon =
                new System.Windows.Forms.NotifyIcon
                    {
                        Icon = Properties.Resources.Application,
                        Text = "Front display",
                        Visible = true
                    };

            _notifyIcon.MouseClick += NotifyIconMouseClick;
            _notifyIcon.DoubleClick += NotifyIconDoubleClick;

            Global.MainPanel.Children.Add(InfoPage.Instance);
            ThemeManager.UpdateControlBackground(InfoPage.Instance);
            ThemeManager.UpdateControlForeground(InfoPage.Instance);

            RegisterHotkeys();

            if (Global.Config.InterceptMouse)
            {
                InterceptMouse.SetMouseHook();
            }

            WindowInteropHelper wndHelper = new WindowInteropHelper(this);
            HwndSource fromHwnd = HwndSource.FromHwnd(wndHelper.Handle);
            if (fromHwnd != null) fromHwnd.AddHook(WindowProc);

            _changeThemeTimer = new DispatcherTimer();
            _changeThemeTimer.Interval = TimeSpan.FromSeconds(Global.Config.ChangeThemeInterval);
            _changeThemeTimer.Tick += delegate { ThemeManager.SelectNext(); };
            if (Global.Config.IsAutoChangeTheme)
            {
                _changeThemeTimer.Start();
            }
        }

        private static void UpgradeConfig()
        {
            if (Global.Config.CallUpgrade)
            {
                Global.Config.Upgrade();
                Global.Config.CallUpgrade = false;
                Global.Config.Save();

                ThemeManager.UpdateBackground();
                ThemeManager.UpdateColors();
                ThemeManager.UpdateThemeColors();

                Def.Localization.CurrentCulture = new CultureInfo(Global.Config.Language);
                
                foreach (var plugin in _plugins)
                {
                    if (plugin.Config != null)
                    {
                        plugin.Config.Upgrade();
                        plugin.Config.Save();
                    }
                }
            }
        }

        private void RegisterHotkeys()
        {
            if (_changeThemeHotkey != null) return;
            _changeThemeHotkey = new Hotkey(Global.Config.ChangeThemeHotkey, ThemeManager.SelectNext);
            _changeThemeHotkey.Register(Application.Current.MainWindow);
        }

        private static void StartPlugins()
        {
            foreach (IPlugin plugin in _plugins)
            {
                try
                {
                    plugin.Start();
                    Logger.Debug("Plugin '" + plugin.GetType() + "' started");
                    plugin.Activated += PluginActivated;
                    plugin.Deactivated += PluginDeactivated;
                }
                catch (Exception ex)
                {
                    Logger.Error(ex);
                }
            }
        }

        private static void InitializePlugins()
        {
            if (_plugins != null) return;

            _plugins = new List<IPlugin> { InfoPage.Instance };

            //TODO: initialization
            Assembly assembly = Assembly.GetExecutingAssembly();
            IEnumerable<Type> pluginsTypes = assembly.GetTypes().Where(t => t.IsClass && !t.IsAbstract && typeof(IPlugin).IsAssignableFrom(t));

            foreach (Type pluginType in pluginsTypes)
            {
                if (pluginType == typeof(InfoPage)) continue;
                _plugins.Add((IPlugin)Activator.CreateInstance(pluginType));
                Logger.Debug(string.Format("{0} created", pluginType));
            }

            Logger.Debug("Plugins created");
        }

        public void UpdateWindowPosition()
        {
            if (Global.Config.IsFullScreen)
            {
                Rectangle bounds = System.Windows.Forms.Screen.AllScreens[Global.Config.DefaultMonitor].Bounds;
                Left = bounds.Left;
                Top = bounds.Top;
                Width = bounds.Width;
                Height = bounds.Height;
                MainPanel.RenderTransform = new ScaleTransform(Width / 800, Height / 500);
            }
            else
            {
                double width = Width;
                double height = Height;
                FrameworkElement border = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;
                if (border != null)
                {
                    width = border.ActualWidth;
                    height = border.ActualHeight;
                }
                MainPanel.RenderTransform = new ScaleTransform(width / 800, height / 500);
            }
        }

        private void NotifyIconDoubleClick(object sender, EventArgs e)
        {
            ParametersMenuItemClick(sender, null);
        }

        private void NotifyIconMouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if ((e.Button & System.Windows.Forms.MouseButtons.Right) == System.Windows.Forms.MouseButtons.Right)
            {
                ContextMenu.IsOpen = true;
                Activate();
            }
        }

        private void MainWindowDeactivated(object sender, EventArgs e)
        {
            ContextMenu.IsOpen = false;
        }

        internal static void ThemeChanged()
        {
            foreach (IPlugin plugin in _plugins)
            {
                plugin.ThemeChanged();
            }
        }

        private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
        {
            if (msg == WinApi.WM_USER + 100)
            {
                double x = ((int)lparam << 16) >> 16;
                double y = (int)lparam >> 16;
                IInputElement control = InputHitTest(new System.Windows.Point(x, y));
                if (control != null)
                {
                    Logger.Info(string.Format("Control {0}", control));
                    if (control is UIElement)
                    {
                        if (wparam == (IntPtr) WinApi.MouseMessages.WM_LBUTTONDOWN)
                        {
                            //RoutedEventArgs args = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left);
                            
                            //control.RaiseEvent(new RoutedEventArgs(UIElement.MouseLeftButtonDownEvent, control));
                        }
                        if (wparam == (IntPtr)WinApi.MouseMessages.WM_LBUTTONUP)
                        {
                            //control.RaiseEvent(new RoutedEventArgs(UIElement.MouseLeftButtonUpEvent, control));
                        }
                        if (wparam == (IntPtr)WinApi.MouseMessages.WM_MOUSEMOVE)
                        {
                            //control.RaiseEvent(new MouseEventArgs(MouseMoveEvent, ));
                        }
                    //    UIElementAutomationPeer peer = new UIElementAutomationPeer((UIElement)control);
                    //    IInvokeProvider invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
                    //    invokeProv.Invoke();
                    //    //ButtonAutomationPeer peer = new ButtonAutomationPeer( (Button) control );
                    //    //IInvokeProvider invokeProv = peer.GetPattern( PatternInterface.Invoke ) as IInvokeProvider;
                    //    //invokeProv.Invoke();
                    }
                }
                //if ((msg >= WinApi.MouseMessages.WM_MOUSEFIRST) && (msg <= WinApi.MouseMessages.WM_MOUSELAST))
                Logger.Info(string.Format("Message {0} wparam {1} lparam {2}x{3}", msg, wparam, x, y));
            }
            return IntPtr.Zero;
        }

        private void MainWindowClosed(object sender, EventArgs e)
        {
            if (Global.Config.InterceptMouse)
            {
                InterceptMouse.RemoveMouseHook();
            }
            foreach (IPlugin plugin in _plugins)
            {
                plugin.Stop();
                Logger.Debug("Plugin '" + plugin.GetType()+ "' stopped");
            }

            SystemEvents.DisplaySettingsChanged -= SystemEventsDisplaySettingsChanged;

            _notifyIcon.Visible = false;
            if (_changeThemeHotkey != null) _changeThemeHotkey.Unregister();
            Global.Config.Save();
        }

        private static void PluginActivated(IPlugin plugin)
        {
            InfoPage.Instance.ShowTopInfo(plugin.TopControl);
            InfoPage.Instance.ShowBottomInfo(plugin.BottomControl);
        }

        private static void PluginDeactivated(IPlugin plugin)
        {
            DeactivatePlugin(plugin, p => p.TopControl);
            DeactivatePlugin(plugin, p => p.BottomControl);
        }

        private static void DeactivatePlugin(IPlugin plugin, Func<IPlugin, UIElement> getControl)
        {
            if (getControl(plugin) != null)
            {
                getControl(plugin).Visibility = Visibility.Collapsed;
            }

            foreach (IPlugin item in _plugins)
            {
                //TODO: create plugins priority
                if ((item != plugin) && (item.IsActive))
                {
                    if (getControl(item) != null)
                    {
                        getControl(item).Visibility = Visibility.Visible;
                        break;
                    }
                }
            }
        }

        private void ExitMenuItemClick(object sender, RoutedEventArgs e)
        {
            Application.Current.Shutdown();
        }

        private void ParametersMenuItemClick(object sender, RoutedEventArgs e)
        {
            if ((_parametersWindow == null) || (!_parametersWindow.IsLoaded))
            {
                _parametersWindow = new ParametersWindow();
            }
            _parametersWindow.Show();
            _parametersWindow.Activate();
        }

        private void SystemEventsDisplaySettingsChanged(object sender, EventArgs e)
        {
            UpdateWindowPosition();
            Application.Current.MainWindow.WindowState = WindowState.Minimized;
            Application.Current.MainWindow.WindowState = WindowState.Normal;
        }

        //private void CapltionMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        //{
        //    DragMove();
        //}
    }
}
